# 装饰器1：登录检查
def check_login(fn_name):
    print(f"check_login:{fn_name.__name__}")
    def inner():
        print("登录中...")
        fn_name()
    return inner

# 装饰器2：验证码检查
def check_code(fn_name):
    print(f"check_code:{fn_name.__name__}")
    def inner():
        print("验证码验证中...")
        fn_name()
    return inner

# 被装饰的函数
@check_login
@check_code
def comment():
    print("发表评论...")

if __name__ == '__main__':
    comment()
    # 等价于
    c = check_login(check_code(comment))
    c()
"""
装饰器应用说明：
    两个装饰器 check_login 和 check_code 都用于增强 comment 函数的功能。
    装饰器按照从上到下的顺序应用，但注意：最上面的装饰器（check_login）实际上是最后执行的，最下面的装饰器（check_code）是最先应用的。这是因为装饰器的应用顺序是自底向上的。

装饰器应用的等价形式：
# 没有装饰器语法糖的等价写法：
    comment = check_login(check_code(comment))

详细步骤分解：
1：首先，应用离函数定义最近的装饰器，即@check_code。所以原始的comment函数被check_code装饰，相当于：
    comment = check_code(comment)
    此时，comment指向了check_code.inner函数，而inner中的fn_name指向原始的comment函数。
2：然后，应用上层的装饰器@check_login，这时它装饰的是已经被check_code装饰过的函数（即上一步返回的inner函数）。相当于：
    comment = check_login(comment)
    此时，comment指向了check_login.inner函数，而inner中的fn_name指向的是上一步返回的check_code.inner函数。
3：当我们调用comment()时，实际上调用的是check_login.inner()。执行过程如下：
    - 首先，在check_login.inner中：
        print("登录中...")
        fn_name() -> 这里fn_name现在是check_code.inner，所以调用check_code.inner()
    - 进入check_code.inner：
        print("验证码验证中...")
        fn_name() -> 这里fn_name是最原始的comment函数，所以调用原始的comment()
    - 进入原始comment函数：
        print("发表评论...")
4：因此，输出顺序为：
    登录中...
    验证码验证中...
    发表评论...
"""
